package com.yq.service.impl;

import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yq.core.annotation.AzerothTable;
import com.yq.core.base.entity.BaseEntity;
import com.yq.core.base.service.BaseService;
import com.yq.core.bean.Sort;
import com.yq.core.util.Page;
import com.yq.service.annotation.AzerothAutoService;
import com.yq.service.dao.BaseMapper;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.*;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.alibaba.druid.util.JdbcSqlStatUtils.getData;


/**
 * 信  息: [yinquan] [2017-05-05] [1.1]
 * 描  述: 基础 service 实现
 */
@AzerothAutoService("baseService")
public abstract class BaseServiceImpl<T, PK extends Serializable> implements BaseService<T, PK> {

    private static Logger logger = LoggerFactory.getLogger(BaseServiceImpl.class);

    private Class<T> entityClass;

    public Class getEntity() {
        return this.entityClass;
    }

    public abstract BaseMapper<T, PK> getBaseMapper();

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    @Autowired
    private BaseMapper baseMapper;

    public BaseServiceImpl() {
        this.entityClass = null;
        Class c = getClass();
        Type type = c.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
    }

    /**
     * 根据ID获取实体对象
     * @param id
     * @return
     */
    public T findUniqueById(PK id) {
        // 所有表的默认主键为uid
        Map<String, Object> parameters = Maps.newHashMap();
        parameters.put("uid", id);
        return findUniqueBy(parameters);
    }

    /**
     * 根据条件获取实体对象
     * @param parameters
     * @return
     */
    public T findUniqueBy(Map<String, Object> parameters) {
        BaseEntity entity = null;
        try {
            //Map<String, Object> data = getData(((T)getEntity()).toString());
            Map<String, Object> obj = baseMapper.findUniqueBy(findUniqueByMap(parameters));
            if(obj!=null) {
                entity = (BaseEntity) getEntity().newInstance();
                for (Map.Entry<String, Object> entry : obj.entrySet()) {
                    // CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey())
                    // eg: delete_state --> deleteState
                    BeanUtils.setProperty(entity, CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getKey()), entry.getValue());
                }
            } else {
                entity = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return (T) entity;
    }
    /**
     * 根据主键获取 Map 对象
     * @param id
     * @return
     */
    public Map<String, Object> findMapUniqueById(String id) {
        // 默认主键 uid
        Map<String, Object> parameters = Maps.newHashMap();
        parameters.put("uid", id);
        return findMapUniqueBy(parameters);
    }
    /**
     * 根据条件获取 Map 对象
     * @param parameters
     * @return
     */
    public Map<String, Object> findMapUniqueBy(Map<String, Object> parameters) {
        Map<String, Object> obj = null;
        try {
            //Map<String, Object> data = getData(((T)getEntity()).toString());
            obj = baseMapper.findUniqueBy(findUniqueByMap(parameters));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
    /**
     * 保存
     * @param t
     * @return ID
     */
    public PK insert(T t) {
        Map<String, Object> entity = Maps.newHashMap();
        try {
            entity = PropertyUtils.describe(t);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (PK) insertEntity(entity);
    }
    public Object insertEntity(Map<String, Object> entity) {
        String uid = baseMapper.uuid();
        entity.put("uid", uid);

        baseMapper.insert(insertEntityMap(entity));
        return uid;
    }
    /**
     * 根据对象更新
     * @param t
     */
    public void update(T t) {
        try{
            baseMapper.update(updateEntityMap(PropertyUtils.describe(t)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 根据条件更新，可批量更新
     * @param parameters
     */
    /*public void update(Map<String, Object> parameters) {
        try{
            Map<String, Object> data = getData(((T)getEntity()).toString());
            //baseMapper.update(updateEntityMap(parameters, data));
        } catch (Exception e) {
        }
    }*/

    /**
     * 查询
     * @param parameters
     * @param page
     */
    public Page<T> paging(Map<String, Object> parameters, Page page) {
        PageBounds pageBounds = new PageBounds(page.getPageCurrent(), page.getPageSize(), true);
        List<Map<String, Object>> list = baseMapper.paging(pagingByMap(parameters), pageBounds);
        PageList<Map<String, Object>> pageList = (PageList) list;
        page.setRows(pageList);
        page.setTotalPageNum(pageList.getPaginator().getTotalPages());// 总页数
        page.setTotal(pageList.getPaginator().getTotalCount());// 总记录数
        return page;
    }

    /** 私有 *********************************************************************/

    /*private Map<String, Object> getData(String entityName) {
        return (Map<String, Object>) BaseData.getConfig(entityName).get("entity");
    }*/

    // update T 设置更新的参数
    private Map<String, Object> updateEntityMap(Map<String, Object> entity) {
        // 最终数据对象
        Map<String, Object> tableObj = Maps.newHashMap();
        // 需要编辑的参数
        Map<String, Object> term = Maps.newHashMap();
        // 获取设置的默认值
        Map<String, Object> pro = Maps.newHashMap();
        // 获取需要过滤的属性
        Map<String, Object> col = Maps.newHashMap();

        // 获取 Entity 类的注解
        AzerothTable at = (AzerothTable) getEntity().getAnnotation(AzerothTable.class);
        // 获取需要过滤的字段
        entityMonthFilter(at, col);

        // 获取 Entity 属性的注解
        entityFilter(pro, "update");

        // 遍历 Entity[Map]，设置默认值，生成可更新的数据
        for (Map.Entry<String, Object> entry : entity.entrySet()) {
            String key = entry.getKey();

            // 发现可以忽略的值时跳出本次循环
            if(col.get(key)!=null) { continue; }

            // CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey())
            // eg: deleteState --> delete_state
            term.put(
                CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key),
                pro.get(key)==null?entry.getValue():pro.get(key)
            );
            if(key.equals("uid")) {
                tableObj.put("uid", entry.getValue());
            }
        }
        tableObj.put("name", at.name());
        tableObj.put("term", term);
        return tableObj;
    }

    // find T 设置查询的参数
    private Map<String, Object> findUniqueByMap(Map<String, Object> parameters) {
        //Map<String, Object> select = (Map<String, Object>) data.get("select"); // 默认值
        Map<String, Object> per = Maps.newHashMap();

        /*for (Map.Entry<String, Object> entry : select.entrySet()) {
            // CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey())
            // eg: deleteState --> delete_state
            parameters.put(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey()), entry.getValue());
        }*/
        // 获取 Entity 类的注解
        AzerothTable at = (AzerothTable) getEntity().getAnnotation(AzerothTable.class);

        per.put("name", at.name());
        per.put("term", parameters);
        return per;
    }

    // searching 搜索设置条件
    private Map<String, Object> pagingByMap(Map<String, Object> parameters) {
        //Map<String, Object> select = (Map<String, Object>) data.get("select"); // 默认值

        Sort sort = new Sort(); // 排序

        Map<String, Object> per = Maps.newHashMap(); // 最终的查询对象
        Map<String, Object> term = Maps.newHashMap(); // 搜索条件

        // 获取 Entity 类的注解
        AzerothTable at = (AzerothTable) getEntity().getAnnotation(AzerothTable.class);
        String sortKey[] = at.sort();
        if(sortKey!=null) {
            sort.setOrder(at.order());
            //sort.setList(Lists.<String>newArrayList());
            for(String key : sortKey) {
                sort.setListChild(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key));
            }
        } else {
            sort = null;
        }

        Field[] fields = getEntity().getDeclaredFields();
        for(Field f : fields) {
            if(f.isAnnotationPresent(AzerothTable.class)) {
                AzerothTable atm = f.getAnnotation(AzerothTable.class);
                if(StringUtils.isNotEmpty(atm.select())) {
                    // CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey())
                    // eg: deleteState --> delete_state
                    term.put(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, f.getName()), atm.select());
                }
            }
        }

        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            // CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey())
            // eg: deleteState --> delete_state
            term.put(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey()), entry.getValue());
        }

        per.put("name", at.name());
        per.put("select", "*");
        per.put("term", term);
        per.put("sort", sort);

        return per;
    }

    // insert T 设置插入的Entity数据
    private Map<String, Object> insertEntityMap(Map<String, Object> entity) {
        // 最终数据对象
        Map<String, Object> tableObj = Maps.newHashMap();
        // 需要设置的字段
        StringBuffer keys = new StringBuffer();
        // 字段对应的属性值
        List<Object> values = Lists.newArrayList();
        // 获取设置的默认值
        Map<String, Object> pro = Maps.newHashMap();
        // 获取需要过滤的属性
        Map<String, Object> col = Maps.newHashMap();

        // 获取 Entity 类的注解
        AzerothTable at = (AzerothTable) getEntity().getAnnotation(AzerothTable.class);
        // 获取需要过滤的字段
        entityMonthFilter(at, col);

        // 获取 Entity 属性的注解
        entityFilter(pro, "insert");

        // 遍历 Entity[Map]，设置默认值，生成可插入的数据
        for(Iterator ite = entity.entrySet().iterator(); ite.hasNext();) {
            Map.Entry map = (Map.Entry) ite.next();
            String key = map.getKey().toString();

            // 发现可以忽略的值时跳出本次循环
            if(col.get(key)!=null) { continue; }

            // 驼峰命名规则转化
            keys.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key)).append(",");

            // 按照 key - value 形式设置参数
            Map<String, Object> temp = Maps.newHashMap();
            temp.put("per", key);
            temp.put("val", pro.get(key)==null?map.getValue():pro.get(key));
            values.add(temp);
        }
        // 设置插入字段
        tableObj.put("field", keys.toString());
        // 设置插入属性
        tableObj.put("values", values);
        // 设置表名称
        tableObj.put("name", at.name());

        return tableObj;
    }

    // 插入、更新 参数默认值获取
    private void entityFilter(Map<String, Object> m, String status) {
        // 获取 Entity 属性的注解
        Field[] fields = getEntity().getDeclaredFields();
        for(Field f : fields) {
            if(f.isAnnotationPresent(AzerothTable.class)) {
                AzerothTable atm = f.getAnnotation(AzerothTable.class);
                if(status.equals("insert") && StringUtils.isNotEmpty(atm.insert())) {
                    m.put(f.getName(), atm.insert());

                } else if(status.equals("update") && StringUtils.isNotEmpty(atm.update())) {
                    m.put(f.getName(), atm.update());
                }
            }
        }
    }
    // 插入、更新 参数过滤
    private void entityMonthFilter(AzerothTable at, Map<String, Object> col) {
        // 过滤需要过滤属性的数组
        String[] filters = at.filter();
        for(String f : filters) {
            col.put(f, "1");
        }
        // Entity 转 Map 时, 会多出class参数
        col.put("class", "1");
    }

    // List<Map<Spring, Object>>转List<T>
    public List<T> ListMapToListBean(List<Map<String, Object>> list) {
        // 返回数据集合
        List<T> listT = Lists.newArrayList();
        try {
            for (Map<String, Object> map : list) {
                BaseEntity entity = (BaseEntity) getEntity().newInstance();
                Field[] fields = entityClass.getDeclaredFields();

                Object uid = map.get("uid");
                if(uid!=null) {
                    BeanUtils.setProperty(entity, "uid", uid);
                }

                for (Field field : fields) {
                    field.setAccessible(true);
                    //Class fieldType = field.getType(); // 获取字段类型
                    String typeName = field.getType().getName(); // 获取属性名字

                    Object paramValue = map.get(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()));
                    if(paramValue==null) {
                        continue;
                    }

                    BeanUtils.setProperty(entity, field.getName(), paramValue);

                    /*if(typeName.startsWith("java.lang")) {
                        BeanUtils.setProperty(entity, field.getName(), paramValue);

                    }  else if(typeName.startsWith("java.util.Date")) {
                        BeanUtils.setProperty(entity, field.getName(), paramValue);

                    } else {
                        System.out.println("typeName="+typeName);
                        BeanUtils.setProperty(entity, field.getName(), paramValue);
                    }*/
                }
                //System.out.println("-------------------------------------------");
                listT.add((T)entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 返回
        return listT;
    }

}
